■ RS232C通信 ( PIC − PIC間 )
PIC同士それぞれのTX、RX端子をタスキがけに直接接続するだけでRS232C通信が可能です。以下に、RS232Cによる
PIC間通信の例を紹介します。
(1) 文字の送受信 (基本編 putc() 、getc() タイムアウト付 )
(2) 文字列の送受信 (基本編 printf() 、getc() )
(3) 文字列の送受信 (応用編 サムチェック、 ハンドシェーク、タイムアウト)
(1) 基本的送受信 ( putc() 、getc() タイムアウト付 )
putc()、get()を使用した簡単なRS232C通信の例を紹介します。
<試作品仕様>
★ データ送信側 PIC
・ 0〜255の整数Xを1秒ごとにインクリメントしながら TX端子からRS232Cで送信する。
・ 液晶の1行目に送信データを表示する。
(例) X = 100
液晶の2行目に受信データを表示する。
(例) Y= 10000
( = X * X )
・ タイムアウト制御をおこなう
★ データ受信側 PIC
・ 受信したデータを 2乗して返信する
・ タイムアウト制御をおこなう
<試作品回路図>(→回路図のPDFファイル)
PIC18F452×2をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
以下のプログラム例の中にある液晶表示器制御ライブラリ 1llcd_lib.cは 後閑哲也さんが設計されたものです。
<プログラム例>
/* 送信側 PIC(液晶付) ・ データXを送信する。 ・ 受信データYを受信する。 ・ 液晶の1行目に送信データXを表示する。 ・ 液晶の2行目に受信データYを表示する。 PIC18F452 + 液晶 → RS232C(5V) → PIC18F452 PIC18F452 + 液晶 ← RS232C(5V) ← PIC18F452 */ #include "18f452.h" #use delay(clock=40000000) // 40MHz(システムクロック周波数)=10MHz(外部発振子周波数)×4(PLL倍率) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // ボーレート = 9600bps TX=RC6,RX=RC7 #define NAK 0x15 // タイムアウトした場合の送信文字としてNAKを使用 #define timeout_Time 100 // タイムアウト時間の設定 : 単位msec #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //rs #define stb PIN_D0 //strobe #include <1lcd_lib.c> unsigned int timed_getc() //タイムアウト付getc() { int32 timeout; unsigned int returnValue; timeout = 0; while(!kbhit()&&(++timeout<timeout_Time*100)) // タイムアウト時間内にデータを受信しなければwhile()ループを抜ける //タイムアウト時間 = 100(10μsec × 100 × 100)msec delay_us(10); // 10μsec if(kbhit()) //タイムアウト時間内にデータを取得した場合はデータを取得し、そのデータを返す returnValue = getc(); else // タイムアウト時間内でデータを取得できなかった場合はNAKを返す returnValue = NAK; return returnValue; } void Tranceiver() { unsigned int X = 0; unsigned long int Y; unsigned int temp1,temp2; for(X = 0; X < 255 ;X++) { putc(X); temp1 = timed_getc(); // 0〜7 ビットデータ temp2 = timed_getc(); // 8〜15 ビットデータ Y = (unsigned long int)temp1 + ((unsigned long int)temp2 << 8); //16ビットにキャストしてからビットシフト lcd_clear(); printf(lcd_data,"X=%u",X); lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Y=%lu (=X*X)",Y); delay_ms(1000); } } main(){ set_tris_c(0b10000000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"First Line !!"); lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Second Line"); delay_ms(500); timed_getc(); // 受信バッファークリア while(1) { Tranceiver(); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home } //******************************************************************************** //******************************************************************************** /* 受信側 PIC(液晶なし) 受信データを二乗して返信 */ //******************************************************************************** //******************************************************************************** #include <18F452.h> #include "string.h" #use delay(clock=40000000) #FUSES EC,NOWDT,,PUT,BROWNOUT,BORV42,NOPROTECT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // ボーレート = 9600bps TX=RC6,RX=RC7 #byte port_PIR1=0x0F9E #define NAK 0x15 // タイムアウトした場合の送信文字としてNAKを使用 #define timeout_Time 1500 // タイムアウト時間の設定 : 単位msec unsigned int timed_getc() //タイムアウト付getc() { int32 timeout; unsigned int returnValue; timeout = 0; while(!kbhit()&&(++timeout<timeout_Time*100)) // タイムアウト時間内にデータを受信しなければwhile()ループを抜ける //タイムアウト時間 = 1500(10μsec × 100 × 1500)msec delay_us(10); // 10μsec if(kbhit()) //タイムアウト時間内にデータを取得した場合はデータを取得し、そのデータを返す returnValue = getc(); else // タイムアウト時間内でデータを取得できなかった場合はNAKを返す returnValue = NAK; return returnValue; } void Tranceiver() // 送受信関数 { unsigned int ReceiveData,Out1,Out2; unsigned long int Out; port_PIR1 = 0x10010000; // フレーミングエラー、オーバーランエラークリア ReceiveData = timed_getc(); Out = (unsigned long int)ReceiveData * (unsigned long int)ReceiveData; Out1 = (unsigned int)Out; Out2 = (unsigned int)(Out >> 8); // 上位16ビットを8ビットビットシフト → 上位8ビットの摘出 putc(Out1); putc(Out2); } main(){ set_tris_c(0b10000000);// 必須 in = RC7 & RC4 while(1) // { Tranceiver(); } return 0; }
<動作結果>
データ送信側PICから送信データとして150を送った時の液晶画面の写真を下記に示します。
受信データ Y=22500は受信側PICが計算した計算結果( 22500=150×150 )です。
(2) 基本的送受信 ( printf() 、getc() ) CCS編 PIC18F452
CCSコンパイラ、C18コンパイラのコンソール標準出力関数printf()にRS232Cが対応しています。 printf()をつかって
文字列を連続してPIC間で送受信する場合、受信側での処理が遅いと送受信がうまくいきません。受信側に液晶がついて
いる場合に受信ごとに表示していると表示処理は時間がかかるため受信がうまくできません。連続して送られてくるデータを
受信ごとには表示せずにいったんメモリに記憶したあと一括して液晶に表示するする例を紹介します。
<試作品仕様>
★ データ送信側 PIC
・300msec毎に下記の2つのデータ1とデータ2を交互におくる
データ1
受信側の1行目用データ …… Transmit Data1
受信側の2行目用データ …… 0123456789012345
データ2
受信側の2行目用データ …… Transmit Data2
受信側の2行目用データ …… abcdefghijklmnop
・データ2を送信したら液晶表示命令として”STX”(= 0x02)を送信する
★ データ受信側 PIC
・ 受信したデータはいったんメモリに記憶する。
・ 液晶表示命令”STX”(= 0x02)を受信したら液晶に表示する
<試作品回路図>(→回路図のPDFファイル)
PIC18F452×2を使用した場合の回路図の例をを下記に示します
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
以下のプログラム例の中にある液晶表示器制御ライブラリ 1llcd_lib.cは 後閑哲也さんが設計されたものです。
<プログラム例>
//**************************************************************** // 送信側 PIC のプログラム //**************************************************************** //PIC18F452+液晶 → RS232C(5V) → PIC16F873+液晶 //3秒毎に文字列データ1、2を交互に送る。 データ1、2にを受信した旨の信号ACK、NACを割込みで受け取り液晶に表示する #include "18f452.h" #use delay(clock=40000000) // 40MHz(システムクロック周波数)=10MHz(外部発振子周波数)×4(PLL倍率) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,RCV=PIN_C7,XMIT=PIN_C6) // ボーレート = 9600bps TX=RC6,RX=RC7, #define STX 0x02 // STX void SendData1() { putc('\r'); // ¥r: 液晶画面をクリア& 文字表示位置を一行目の先頭へ移動 printf("Transmit Data1 "); //文字データを送信 putc('\n'); // ¥n: 文字表示位置を2行目の先頭へ printf("0123456789012345");//文字データを送信 putc(STX);// 液晶画面表示 } void SendData2() { putc('\r'); // ¥r: 液晶画面をクリア& 文字表示位置を一行目の先頭へ移動 printf("Transmit Data2 "); //文字データを送信 putc('\n'); // ¥n: 文字表示位置を2行目の先頭へ printf("abcdefghijklmnop");//文字データを送信 putc(STX);// 液晶画面表示 } main(){ set_tris_c(0b10000000);// 必須 in = RC7 delay_ms(1000); //受信側が受信完了まで待つ while(1) { SendData1(); delay_ms(3000); SendData2(); delay_ms(3000); } return 0; } //****************************************************************** // 受信側 PIC //****************************************************************** #include <18F452.h> #use delay(clock=40000000) #FUSES EC,NOWDT,,PUT,BROWNOUT,BORV42,NOPROTECT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // TX=RC6,RX=RC7 #define STX 0x02 // STX #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> int n = 0,i=0; char RX1[17],RX2[17]; char RX1_LCD[17],RX2_LCD[17]; int data1; int LineMode = 1; void LCD() { data1 = getc(); switch(data1) { case '\r': LineMode = 1; // 1行目のモード n = 0; // 文字送信順番リセット break; case '\n': // lcd_cmd(0xC0); case 0x0a: LF('\n')なら 2行目の先頭へ LineMode = 2; n = 0; // 文字送信順番リセット break; case STX: // 表示開始命令 for(i = 0; i < 16; i++) { RX1_LCD[i] = RX1[i]; //1行目のデータ RX1_LCD[16] = '\0'; RX2_LCD[i] = RX2[i]; //2行目のデータ RX2_LCD[16] = '\0'; } lcd_clear(); //液晶クリア printf(lcd_data,RX1_LCD); //1行目のデータを一括液晶表示 lcd_cmd(0xC0); //2行目の先頭へ printf(lcd_data,RX2_LCD); //2行目データを一括液晶表示 break; default: switch(LineMode) { case 1: //1行目のデータ RX1[n] = data1; break;//1行目データをメモリに記憶 case 2: //2行目のデータ RX2[n] = data1; break;//2行目データをメモリに記憶 default: break; } n++; break; } } main(){ lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"First Line"); lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Second Line"); delay_ms(500); while(1) { if(kbhit()) LCD(); //RS232Cのデータ(1バイト)が受信完了しているなら LCD()実行 } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
受信側PICに接続されている液晶画面の写真を示します。
データ1
受信側の1行目用データ …… Transmit Data1
受信側の2行目用データ …… 0123456789012345
データ2
受信側の1行目用データ …… Transmit Data2
受信側の2行目用データ …… abcdefghijklmnop
データ1受信時 | データ2受信時 | |
★ PIC-PIC間 RS232C通信 < C30 PIC24編>
PIC24F間のRS232C通信の例を紹介します。
<試作品の仕様>
・PIC24F間nRS232C通信をおこなう
・送信側PIC24F側からはタイマで順次文字列を送信する。。
送信される文字の最後尾には’¥r’付加する。
PIC側ではこれらの文字列を受信したら以下の文字列をPC側に返信する。
Sakamoto
→ Ryouma
Saigou → Takamori
Katsura
→ Kogorou
その他
→ Pardon?
・ 受信側PICでは受信文字列、返信文字列を液晶に表示する。
・ 送信側PICでも送信文字列、受信文字列を液晶に表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC24FJ64GA002を使用した場合の回路図の例をを下記に示します
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //RS232C 送受信(割り込み有り) // PIC−PIC 間 PIC24FJ64GA002 〜 PIC24FJ64GA002 //送信側 #include "p24FJ64GA002.h" #include <stdio.h> #include <uart.h> #include <timer.h> #include "1lcd_lib_C30.h" #include "1lcd_lib_c30.c" /// コンフィギュレーション ビットの設定 _CONFIG1 ( JTAGEN_OFF & //JTAGポート: OFF GCP_OFF & //コードプロテクト: OFF GWRP_OFF & //書き込みプロテクト: OFF BKBUG_OFF & //バックグランドデバック: OFF COE_OFF & //クリップオン エミュレーション: OFF ICS_PGx1& //ICDピンの選択: EMUC/EMUDをPGC1/PGD1と共用 FWDTEN_OFF //ウォッチドックタイマ: OFF ) _CONFIG2 ( FNOSC_PRI & //外付け発振子20MHZ PLLなし → システムクロック:20MHZ POSCMOD_HS //発振回路モード Oscillator Selection: HS (外付け発振回路 発振周波数レベル:HS) ) int i = 0; char buf[20]; char Buf[20]; char Saigou[] = "Saigou"; char Katsura[] = "Katsura"; char Sakamoto[] = "Sakamoto"; char Tokyo[] = "Tokyo"; char* str; char Space = ' '; int count_time = 0; unsigned int count_N = 0; void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/2000*N); } void _ISR _T1Interrupt(void) //100msec毎の割込み発生 { IFS0bits.T1IF = 0; //IFS0レジスタの T1IF(タイマ1の割込み検出)フラグリセット count_time++; if(count_time >= 30) //3秒経ったら { count_time = 0; if(count_N < 1) { printf(Saigou); // 文字列Saigou をに一括送信 putcUART1('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Saigou); // 開始メッセージ1行目表示 } else if(count_N < 2) { printf(Katsura); putcUART1('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Katsura); // 開始メッセージ1行目表示 } else if(count_N < 3) { printf(Sakamoto); putcUART1('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Sakamoto); // 開始メッセージ1行目表示 } else { printf(Tokyo); putcUART1('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Tokyo); // 開始メッセージ1行目表示 } count_N++; if(count_N >= 4)count_N = 0; } } void _ISR _U1RXInterrupt(void) //RS232C 受信割込み { IFS0bits.U1RXIF = 0; //受信割込みフラグクリア while(!DataRdyUART1()); //UARTバッファーにデータがくるまでまつ buf[i] = getcUART1(); if(buf[i] == '\r') // '\r'を受信した場合 { buf[i] = '\0'; //液晶に出力 sprintf(Buf,"%s%c",&buf[0],Space);//arguementがないと遅い C30のバグ? lcd_cmd(0xc0); //1行目へ lcd_str(Buf); //液晶表示 // lcd_str(&buf[0]); // このコードでは遅い!! i = 0; } else //'\r'以外を受信した場合 { i++; } } main() { CLKDIV = 0; // set 1:1 AD1PCFG = 0xFFFF; // ポートA全ディジタルに指定//ANxのポートすべてに対して必須 TRISB = 0b0000000000001000; // ポートB RB3:RXは入力に 、その他RB5:SDA、RB6:SCL等は出力に設定 // UART1ピン割付 リマッピング RPINR18bits.U1RXR = 3; // UART1 RX to RP3 RPOR1bits.RP2R = 3; // UART1 TX to RP2 /// UART1初期設定 9600bps 8ビット パリティなし、フロー制御なし U1BRG = 64; // 9600bps at システムクロック20MHz //U1BRG = (Fosc(Hz)/2/16/baud(bps) - 1 // = 20000000/2/16/9600 - 1 = 64.1 → 64) U1MODE = 0b1000100000000000; // UART1初期設定 //U1MODEレジスタ設定 U1STA = 0b0000010000000000; // UART1初期設定 //U1STAレジスタ設定 /// タイマ1: 周期 100msec OpenTimer1(T1_ON & //タイマ1ON T1_GATE_OFF & //ゲート制御off T1_PS_1_256 & //プリスケーラ 1/256 T1_SYNC_EXT_OFF & //クロック同期制御OFF T1_SOURCE_INT, //クロック源:内部クロック T1_SOURCE_INT: Internal clock source 6249); //100msec→10×1000×(32MHz/2MHz)/256=6250 PR1設定値=6249( = 6250 - 1 ) //24Fは2システムクロックが1命令である lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"RS232C Master !!%c",Space);//arguementがないと遅い C30のバグ? lcd_cmd(0x80); //1行目へ lcd_str(Buf); //液晶表示 delay_ms(1000); ConfigIntTimer1(T1_INT_PRIOR_5 & T1_INT_ON); //割込みレベル5 タイマ1割込みON EnableIntT1; //割込み許可 SetPriorityIntU1RX(6);//RS232C受信割込みON レベル6 //数字が大きい方が割込み優先度高 EnableIntU1RX; //受信割込み許可 while(1) { if(U1STAbits.OERR || U1STAbits.FERR) { U1STA &= 0xFFF0; //オーバーランエラー、フレーミングエラー、パリティエラークリア U1MODEbits.UARTEN = 0; //UARAT初期化 U1MODEbits.UARTEN = 1; } } return 0; } //************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等でに変更したものです。 //************************************************************************* #include "p24FJ64GA002.h" #define Clock 20000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB15 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB14 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB13 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB12 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATBbits.LATB1 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATBbits.LATB0 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 2000000); // 1μsecに要するウェイト回数 _50usec = (unsigned int)(Clock / 2000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 2000); // 1msecに要するウェイト回数 // = Clock / 2000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home } //---------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------- //返信側 プログラム //RS232C 送受信(割り込みなし) 返信側 // PC−PIC 間 PIC24FJ64GA002 #include "p24FJ64GA002.h" #include <stdio.h> #include <uart.h> #include "1lcd_lib_C30.h" #include "1lcd_lib_c30.c" /// コンフィギュレーション ビットの設定 _CONFIG1 ( JTAGEN_OFF & //JTAGポート: OFF GCP_OFF & //コードプロテクト: OFF GWRP_OFF & //書き込みプロテクト: OFF BKBUG_OFF & //バックグランドデバック: OFF COE_OFF & //クリップオン エミュレーション: OFF ICS_PGx1& //ICDピンの選択: EMUC/EMUDをPGC1/PGD1と共用 FWDTEN_OFF //ウォッチドックタイマ: OFF ) _CONFIG2 ( FNOSC_PRI & //外付け発振子20MHZ PLLなし → システムクロック:20MHZ POSCMOD_HS //発振回路モード Oscillator Selection: HS (外付け発振回路 発振周波数レベル:HS) ) int i = 0; char buf[20]; char Buf[20]; char Saigou[] = "Saigou"; char Takamori[] = "Takamori"; char Katsura[] = "Katsura"; char Kogorou[] = "Kogorou"; char Sakamoto[] = "Sakamoto"; char Ryouma[] = "Ryouma"; char Pardon[] = "Pardon?"; char* str; char Space = ' '; void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/2000*N); } void LCD() //受信&液晶表示 { while(!DataRdyUART1()); //UARTバッファーにデータがくるまでまつ buf[i] = getcUART1(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Sakamoto) == 0)str = Ryouma; else if(strcmp(buf,Saigou) == 0) str = Takamori; else if(strcmp(buf,Katsura) == 0) str = Kogorou; else str = Pardon; printf(str); // 返信を 文字列としてPCに一括送信 putcUART1('\r'); // 文字列終端制御文字を送信 //液晶に出力 lcd_clear(); //全消去 lcd_str(&buf[0]); // 開始メッセージ1行目表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"%s%c",str,Space); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ2行目表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main() { CLKDIV = 0; // set 1:1 AD1PCFG = 0xFFFF; // ポートA全ディジタルに指定//ANxのポートすべてに対して必須 TRISB = 0b0000000000001000; // ポートB RB3:RXは入力に 、その他RB5:SDA、RB6:SCL等は出力に設定 // UART1ピン割付 リマッピング RPINR18bits.U1RXR = 3; // UART1 RX to RP3 RPOR1bits.RP2R = 3; // UART1 TX to RP2 /// UART1初期設定 9600bps 8ビット パリティなし、フロー制御なし U1BRG = 64; // 9600bps at システムクロック20MHz //U1BRG = (Fosc(Hz)/2/16/baud(bps) - 1 // = 20000000/2/16/9600 - 1 = 64.1 → 64) U1MODE = 0b1000100000000000; // UART1初期設定 //U1MODEレジスタ設定 U1STA = 0b0000010000000000; // UART1初期設定 //U1STAレジスタ設定 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"RS232C Start !!%c",Space);//arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 delay_ms(1000); while(1) { LCD(); } return 0; } //************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等でに変更したものです。 //************************************************************************* #include "p24FJ64GA002.h" #define Clock 20000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB15 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB14 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB13 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB12 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATBbits.LATB1 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATBbits.LATB0 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 2000000); // 1μsecに要するウェイト回数 _50usec = (unsigned int)(Clock / 2000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 2000); // 1msecに要するウェイト回数 // = Clock / 2000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
送信文字 | 返信文字 | 液晶表示 上側 …… 送信側液晶 @1行目: 送信文字列 A2行目: 受信文字列 下側 …… 受信側液晶 @1行目: 受信文字列 A2行目: 返信文字列 |
Saigou |
Takamori |
|
Katsura |
Kogorou |
|
Sakamoto | Ryouma | |
Tokyo |
Pardon |
★ PIC-PIC間 RS232C通信 < C32 PIC32MX編>
PIC32MX間のRS232C通信の例を紹介します。
<試作品の仕様>
・PIC32MX間のRS232C通信をおこなう
・送信側PIC32MX側からはタイマで順次文字列を送信する。。
送信される文字の最後尾には’¥r’付加する。
PIC側ではこれらの文字列を受信したら以下の文字列をPC側に返信する。
Sakamoto
→ Ryouma
Saigou → Takamori
Katsura
→ Kogorou
その他
→ Pardon?
・ 受信側PICでは受信文字列、返信文字列を液晶に表示する。
・ 送信側PICでも送信文字列、受信文字列を液晶に表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC32MX460512Lを使用した場合の回路図の例をを下記に示します
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> // UART PIC-PIC //割り込み方式(送信側) // PIC32MX460F512L #include <proc/p32mx460f512l.h> //PIC32MX460F512L #include <plib.h> // PIC32 peripheral library //for SYSTEMConfigPerformance() #include <stdio.h> #include "1lcd_lib_C32.h" // Configuration // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 //#define timeout_Time 1000 // タイムアウト時間の設定 : 単位msec #define timeout_count 1000 int i = 0; char buf[20]; char Buf[20]; char Saigou[] = "Saigou"; char Katsura[] = "Katsura"; char Sakamoto[] = "Sakamoto"; char Tokyo[] = "Tokyo"; char* str; char Space = ' '; int count_time = 0; unsigned int count_N = 0; void delay_us(unsigned int usec) //1μsec遅延関数 { int count; count = (int)(Clock/20000000)*usec; do //実測: at Clock=80000000 { //delay_us(1000)→1003μsec、 delay_us(100)→102μsec、delay_us(10)→11μsec、delay_us(1)→1.6μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void delay_ms(unsigned int msec) //1msec遅延関数 { unsigned int i; for(i=0; i<msec; i++) delay_us(1000); } /* void ERR_clear() //エラークリア { if((U2STAbits.OERR || U2STAbits.FERR)) { U2STA = 0; //ステータスレジスタリセット//エラーフラグ等クリア U2MODEbits.ON = 0; //UART:無効化 U2MODEbits.ON = 1; //UART:有効化 } } */ void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void) { //int timeout = 0; if(mU2RXGetIntFlag()) // RXの割り込み? { mU2RXClearIntFlag(); // 割り込みフラグクリア // while(!kbhit()&&(++timeout<timeout_Time*100)) // タイムアウト時間内にデータを受信しなければwhile()ループを抜ける //while((!DataRdyUART2()) && (++timeout < timeout_Time*100)); buf[i] = getcUART2(); if(buf[i] == '\r') // '\r'を受信した場合 { buf[i] = '\0'; //液晶に出力 sprintf(Buf,"%s%c",&buf[0],Space);//arguementがないと遅い C30のバグ? lcd_cmd(0xc0); //1行目へ lcd_str(Buf); //液晶表示 i = 0; } else //'\r'以外を受信した場合 { i++; } } } int main(void) { SYSTEMConfigPerformance(80000000); // システム最適化 TRISE = 0; TRISFbits.TRISF4 = 1; TRISFbits.TRISF5 = 0; OpenUART2 //UART2の設定(U2MODEレジスタ,U2STAレジスタ,U2BRGレジスタの設定) ( UART_EN | // Module Enable // UART enable/disable UART_IDLE_CON | // Work in IDLE mode // UART_IDLE_CON UART_RX_TX | // Communication through usual pins //UART communication with ALT pins UART_DIS_WAKE | // Disable wake-up //UART Wake-up on Start UART_DIS_LOOPBACK | // Loop back disabled //UART Loopback mode enable/disable UART_DIS_ABAUD | // Input to Capture module from ICx pin//Input to Capture module UART_NO_PAR_8BIT | // no parity 8 bit // Parity and data bits select UART_1STOPBIT | // 1 stop bit// Number of Stop bits UART_IRDA_DIS | // IRDA encoder and decoder disabled //IRDA Enable/Disable UART_DIS_BCLK_CTS_RTS| // CTS and RTS pins are disabled UART_MODE_SIMPLEX | //RTS Mode Select UART_NORMAL_RX | //Recievie Polarity UART_BRGH_SIXTEEN, //BRGH = 16 //High Baud Rate Select UART_TX_PIN_LOW | //UART Transmit Break bit UART_TX_ENABLE | //UART transmit enable/disable UART_RX_ENABLE | //UART recieve enable/disable UART_INT_RX_CHAR | //UART Receive Interrupt mode select UART_ADR_DETECT_DIS| //UART address detect enable/disable UART_RX_OVERRUN_CLEAR, // Rx Buffer Over run status bit clear //UART OVERRUN bit clear (unsigned int)(80000000/16/9600-1) // = Fosc/BRGH/Baud Rate -1 //baud rate: 9600bps ); setbuf(stdout,NULL); //Line buffering off lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"PI32MX795F460L");// lcd_str(Buf); //液晶に表示 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN); //UART2割り込みレベルをレベル2に設定 INTEnableSystemMultiVectoredInt(); //マルチベクトル割り込み許可 while(1) { printf(Saigou); // 文字列Saigou をに一括送信 putcUART2('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Saigou); // 開始メッセージ1行目表示 delay_ms(3000); printf(Katsura); putcUART2('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Katsura); // 開始メッセージ1行目表示 delay_ms(3000); printf(Sakamoto); putcUART2('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Sakamoto); // 開始メッセージ1行目表示 delay_ms(3000); printf(Tokyo); putcUART2('\r'); // 文字列終端制御文字を送信 lcd_clear(); //全消去 lcd_cmd(0x80); //1行目へ lcd_str(Tokyo); // 開始メッセージ1行目表示 delay_ms(3000); // ERR_clear(); //永久ループ } } //************************************************************************* //インクルードファイル 1lcd_lib_C32.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************* #include <proc/p32mx460f512l.h> //PIC32MX460F512L //#include <proc/p32mx795f512l.h> //PIC32MX460F512L #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATEbits.LATE7 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATEbits.LATE6 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATEbits.LATE5 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATEbits.LATE4 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATEbits.LATE3 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATEbits.LATE2 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C32.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C32コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C32.h" void lcd_delay_us(unsigned int usec) //1μsec遅延関数 { int count; count = (int)(Clock/20000000)*usec; do { asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void lcd_delay_ms(unsigned int msec) //1msec遅延関数 { unsigned int i; for(i=0; i<msec; i++) lcd_delay_us(1000); } //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 lcd_delay_us(1); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) lcd_delay_us(1); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 lcd_delay_us(50); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 lcd_delay_ms(2); // 2msec待ち else lcd_delay_us(50); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { lcd_delay_ms(20); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(5); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set lcd_delay_ms(1); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home } // UART PC-PIC //割り込み方式(返信側) // PIC32MX460F512L #include <proc/p32mx460f512l.h> //PIC32MX795F512L #include <plib.h> // PIC32 peripheral library //for SYSTEMConfigPerformance() #include <stdio.h> #include "1lcd_lib_C32.h" // Configuration // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 int i = 0; char buf[20]; char Buf[20]; char Saigou[] = "Saigou"; char Takamori[] = "Takamori"; char Katsura[] = "Katsura"; char Kogorou[] = "Kogorou"; char Sakamoto[] = "Sakamoto"; char Ryouma[] = "Ryouma"; char Pardon[] = "Pardon?"; char* str; char Space = ' '; void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void) { mU2RXClearIntFlag(); // 割り込みフラグクリア while(!DataRdyUART2()); //UARTバッファーにデータがくるまでまつ buf[i] = getcUART2(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Sakamoto) == 0)str = Ryouma; else if(strcmp(buf,Saigou) == 0) str = Takamori; else if(strcmp(buf,Katsura) == 0) str = Kogorou; else str = Pardon; printf(str); // 返信を 文字列としてPCに一括送信 putcUART2('\r'); // 文字列終端制御文字を送信 //液晶に出力 lcd_clear(); //全消去 lcd_str(&buf[0]); // 開始メッセージ1行目表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"%s%c",str,Space); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ2行目表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } int main(void) { SYSTEMConfigPerformance(80000000); // システム最適化 TRISE = 0; TRISFbits.TRISF4 = 1; TRISFbits.TRISF5 = 0; OpenUART2 //UART2の設定(U2MODEレジスタ,U2STAレジスタ,U2BRGレジスタの設定) ( UART_EN | // UART enable/disable // UART_RX_TX | //UART communication with ALT pins // UART_DIS_WAKE | //UART Wake-up on Start // UART_DIS_LOOPBACK | //UART Loopback mode enable/disable // UART_DIS_ABAUD | //Input to Capture module UART_NO_PAR_8BIT | // Parity and data bits select UART_1STOPBIT | // Number of Stop bits // UART_IRDA_DIS | //IRDA Enable/Disable // UART_MODE_SIMPLEX | //RTS Mode Select // UART_MODE_FLOWCTRL | //RTS Mode Select // UART_DIS_BCLK_CTS_RTS | // // UART_NORMAL_RX | //Recievie Polarity UART_BRGH_SIXTEEN, //BRGH = 16 //High Baud Rate Select // UART_INT_TX_BUF_EMPTY | //UART Transmission mode interrupt flag select // UART_TX_PIN_LOW | //UART Transmit Break bit UART_TX_ENABLE | //UART transmit enable/disable UART_RX_ENABLE , //UART recieve enable/disable // UART_INT_RX_CHAR | //UART Receive Interrupt mode select // UART_ADR_DETECT_DIS | //UART address detect enable/disable // UART_RX_OVERRUN_CLEAR //UART OVERRUN bit clear (unsigned int)(80000000/16/9600-1) // = Fosc/BRGH/Baud Rate -1 //baud rate: 9600bps ); setbuf(stdout,NULL); //Line buffering off lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"PI32MX460F512L");//C30とは異なり、arguement 不要 lcd_str(Buf); //液晶に表示 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN); //UART2割り込みレベルをレベル2に設定 INTEnableSystemMultiVectoredInt(); //マルチベクトル割り込み許可 while(1) { //永久ループ } } //************************************************************************* //インクルードファイル 1lcd_lib_C32.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************* #include <proc/p32mx460f512l.h> //PIC32MX460F512L //#include <proc/p32mx795f512l.h> //PIC32MX460F512L #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATEbits.LATE7 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATEbits.LATE6 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATEbits.LATE5 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATEbits.LATE4 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATEbits.LATE3 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATEbits.LATE2 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); // UART PC-PIC //割り込み方式(返信側) // PIC32MX460F512L #include <proc/p32mx460f512l.h> //PIC32MX795F512L #include <plib.h> // PIC32 peripheral library //for SYSTEMConfigPerformance() #include <stdio.h> #include "1lcd_lib_C32.h" // Configuration // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 int i = 0; char buf[20]; char Buf[20]; char Saigou[] = "Saigou"; char Takamori[] = "Takamori"; char Katsura[] = "Katsura"; char Kogorou[] = "Kogorou"; char Sakamoto[] = "Sakamoto"; char Ryouma[] = "Ryouma"; char Pardon[] = "Pardon?"; char* str; char Space = ' '; void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void) { mU2RXClearIntFlag(); // 割り込みフラグクリア while(!DataRdyUART2()); //UARTバッファーにデータがくるまでまつ buf[i] = getcUART2(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Sakamoto) == 0)str = Ryouma; else if(strcmp(buf,Saigou) == 0) str = Takamori; else if(strcmp(buf,Katsura) == 0) str = Kogorou; else str = Pardon; printf(str); // 返信を 文字列としてPCに一括送信 putcUART2('\r'); // 文字列終端制御文字を送信 //液晶に出力 lcd_clear(); //全消去 lcd_str(&buf[0]); // 開始メッセージ1行目表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"%s%c",str,Space); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ2行目表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } int main(void) { SYSTEMConfigPerformance(80000000); // システム最適化 TRISE = 0; TRISFbits.TRISF4 = 1; TRISFbits.TRISF5 = 0; OpenUART2 //UART2の設定(U2MODEレジスタ,U2STAレジスタ,U2BRGレジスタの設定) ( UART_EN | // UART enable/disable // UART_RX_TX | //UART communication with ALT pins // UART_DIS_WAKE | //UART Wake-up on Start // UART_DIS_LOOPBACK | //UART Loopback mode enable/disable // UART_DIS_ABAUD | //Input to Capture module UART_NO_PAR_8BIT | // Parity and data bits select UART_1STOPBIT | // Number of Stop bits // UART_IRDA_DIS | //IRDA Enable/Disable // UART_MODE_SIMPLEX | //RTS Mode Select // UART_MODE_FLOWCTRL | //RTS Mode Select // UART_DIS_BCLK_CTS_RTS | // // UART_NORMAL_RX | //Recievie Polarity UART_BRGH_SIXTEEN, //BRGH = 16 //High Baud Rate Select // UART_INT_TX_BUF_EMPTY | //UART Transmission mode interrupt flag select // UART_TX_PIN_LOW | //UART Transmit Break bit UART_TX_ENABLE | //UART transmit enable/disable UART_RX_ENABLE , //UART recieve enable/disable // UART_INT_RX_CHAR | //UART Receive Interrupt mode select // UART_ADR_DETECT_DIS | //UART address detect enable/disable // UART_RX_OVERRUN_CLEAR //UART OVERRUN bit clear (unsigned int)(80000000/16/9600-1) // = Fosc/BRGH/Baud Rate -1 //baud rate: 9600bps ); setbuf(stdout,NULL); //Line buffering off lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"PI32MX460F512L");//C30とは異なり、arguement 不要 lcd_str(Buf); //液晶に表示 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN); //UART2割り込みレベルをレベル2に設定 INTEnableSystemMultiVectoredInt(); //マルチベクトル割り込み許可 while(1) { //永久ループ } }
<動作結果>
送信文字 | 返信文字 | 液晶表示 上側 …… 送信側液晶 @1行目: 送信文字列 A2行目: 受信文字列 下側 …… 受信側液晶 @1行目: 受信文字列 A2行目: 返信文字列 |
Saigou |
Takamori |
|
Katsura |
Kogorou |
|
Sakamoto | Ryouma | |
Tokyo |
Pardon |
(3) 文字列の送受信 (応用編 サムチェック、ハンドシェーク、タイムアウト)
送受信データは壊れることがあります。原因としては以下のようなものがあります。
・ノイズによる伝送波形の乱れ及び送受信回路の誤動作
・スイッチなどの外部割込みやタイマ割込みによる送信側、受信側のソフトウェア割込みに起因する外乱
・受信側の処理能力不足
・送受信のタイミング不良
・エラーレートが大きいための誤動作
他
送信データに誤りがないか受信側でチェックする方法にサムチェック(Sum Check)と云う方法があります。送信側と受信
側で送信データを加算し、一致した場合は誤りがないと判断する誤り検出アルゴリズムのひとつです。また通信の確実性を
高める方法として送信側と受信側が絶えず”確認信号”を交換しながら通信を行うハンドシェークと云う方法があります。
以下に サムチェックによる誤り検出、タイムアウト制御及びハンドシェークにより確実性を高めた通信の例を紹介します。
<試作品仕様>
★ データ送信側 PIC
・ 受信側液晶の1行目表示用データとして 0〜65535の整数を300msec毎にインクリメントしながら送る。インクリメントは
受信側PICからACK(=0x06)が送られてきたことを確認した後におこなう。ACK以外の文字が返信されてきた場合は同じ
整数を再送信する。但し、5回再送信を繰り返してもACKが送られてこない場合はインクリメントをおこなって次の整数を
送る。
(例) 送信データ …… Counts=2568
・ 受信側液晶の2行目表示用データとして ”abcdefghijklimopq”を送る。
・ データのヘッダーとしてESC ( = 0x1b ) とSTX ( = 0x02 )を送る
・ 送信データをバイト毎に加算して加算結果を送信データの後に追加する。
・ 送受信データは32バイト(=16バイト×2)の固定長とする。 すなわち 全送信データは合計36バイト固定長の以下と
する。
ESC + STX + データ(32バイト) + データ加算値の下位8ビット + データ加算値上位8ビット
・ モメンタリースイッチを1つもうけ任意のタイミングでLEDを点灯できるようにする。 外乱生成を目的として任意のタイミ
ングで外部割込みをかけられるようにする。
・ タイムアウト制御をおこなう。
★ データ受信側 PIC
・ 受信したデータはいったんメモリに記憶する。
・ 受信データをバイト毎に加算して送信側PICで計算したデータと比較して、同一で あれば液晶に表示して ACKを
返信する。 同一でなければ受信データは破棄しNAK(=0x15)を返信し、再送信を要求する。
・ タイムアウト制御をおこなう
<試作品回路図>(→回路図のPDFファイル)
PIC18F452×2をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //**************************************************************** // 送信側 PIC プログラム //**************************************************************** //PIC18F452+液晶 → RS232C(5V) → PIC16F873+液晶 #include "18f452.h" #include <string.h> #use delay(clock=40000000) // 40MHz(システムクロック周波数)=10MHz(外部発振子周波数)×4(PLL倍率) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,RCV=PIN_C7,XMIT=PIN_C6) // ボーレート = 9600bps TX=RC6,RX=RC7, #define STX 0x02 // STX #define ETX 0x03 // ETX #define ENQ 0x05 // ENQ #define ACK 0x06 // ACK #define NAK 0x15 // NAK #define ESC 0x1b // ESC #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> #byte port_PIR1=0x0F9E unsigned long int Count = 0; char buf1[]=" ", //液晶の1行目用 …… 文字列リテラルとして17バイト分ブランクで初期化 buf2[]=" "; //液晶の2行目用 …… 文字列リテラルとして17バイト分ブランクで初期化 int LED1 = 0; unsigned int NG_Count = 0; char timed_getc() { char returnValue; int32 timeout; timeout = 0; while(!kbhit()&&(++timeout< 100000)) // タイムアウト時間内にデータを受信しなければwhile()ループを抜ける //タイムアウト時間 = 1000 msec delay_us(10); // 10μsec if(kbhit()) //タイムアウト時間内にデータを取得した場合はデータを取得し、そのデータを返す returnValue = getc(); else // タイムアウト時間内でデータを取得できなかった場合はNAKを返す returnValue = NAK; return returnValue; } void Transmit(char* buf1,char* buf2) // 送信関数 { int i; unsigned long int TotalSum; unsigned int sum[2]; putc(ESC);//ESCを送信 putc(STX);//STXを送信 printf("%s",buf1); // buf1(16バイト固定長)を16バイト送信 (NULL'\0'は送信されない) printf("%s",buf2); // buf2(16バイト固定長)を16バイト送信 (NULL'\0'は送信されない) TotalSum = 0; for(i = 0; i < 16; i ++) TotalSum = TotalSum + (unsigned int)buf1[i] + (unsigned int)buf2[i]; //サムの計算 sum[0] = (unsigned int)TotalSum; sum[1] = (unsigned int)(TotalSum >> 8); putc(sum[0]); //サムデータの下位8ビットを送信 putc(sum[1]); //サムデータの上位8ビットを送信 } void Tranceiver() { char Response; sprintf(buf1,"Count=%lu",Count);//符号無ロング整数を文字列に変換 vs Count = atol(s1) // sprintf(s1,"%d" ,Count) vs Count = atoi(s1) // sprintf(s1,"%f",Vaule) Vs Value = atof(s1) buf1[strlen(buf1)] = ' '; //文字列buf1の終端のNULL'\0'をSPACE' 'に変更 buf1[16] ='\0'; //文字列buf1を16バイトの文字列に変換 sprintf(buf2,"abcdefghijklmopq");// 文字列長さ=16バイト : sprintf()はbuf2[16]にNULL'\0'をセット do { Transmit(buf1,buf2); Response = timed_getc(); lcd_clear(); if(Response == ACK)printf(lcd_data,"Response=ACK");//ACKが返ってきたら液晶にResponse=ACKと表示 else if(Response == NAK)printf(lcd_data,"Response=NAK"); else { printf(lcd_data,"Response=%x",Response); //ACK NAK以外が返ってきたら返ってきた文字をアスキーコードで表示 } lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Counts=%lu",Count); NG_Count ++; }while((Response != ACK) && (NG_Count < 5)); // ACKが返信されてくるまで または5回の再送信まで送信を繰り返す NG_Count = 0; delay_ms(300); Count = Count +1; //送信する整数をインクリメント if(Count >= 65520) Count = 0; } #INT_EXT1 void EXTX1() // スイッチによる外乱(外部割込み) { delay_ms(50); if(input(PIN_B1) == 0) { if(LED1 == 1) { LED1 = 0; output_high(PIN_B5); //RB5,6,7LED 消灯 output_high(PIN_B6); output_high(PIN_B7); } else { LED1 = 1; output_low(PIN_B5); // RB5,6,7 LED 点灯 output_low(PIN_B6); output_low(PIN_B7); } } } main(){ set_tris_c(0b10000000);// 必須 in = RC7 ext_int_edge( 1, H_TO_L); // Set up PIC18 EXT1 //RB1(INT1)ポートが highからlowに変化した時割込みがかかるように設定 LED1 = 1; output_low(PIN_B5); // 電源投入でLED消灯 output_low(PIN_B6); // 電源投入でLED消灯 output_low(PIN_B7); // 電源投入でLED消灯 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"Master First"); lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Master Second"); timed_getc(); // 受信バッファークリア (重要) enable_interrupts(INT_EXT1); //RB1からの外部割込みを許可 enable_interrupts(GLOBAL); // すべての割り込みを許可 while(1) { Tranceiver(); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home } //------------------------------------------------------------------------- //********************************************************* //受信側PIC プログラム //********************************************************* //サムチェック → OKなら液晶に表示、ACKを返信 // → NGならデータは棄てる、NACKを返信 #include <18F452.h> #include <string.h> #use delay(clock=40000000)//40MHz #FUSES HS,NOWDT,PUT,BROWNOUT,NOPROTECT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // TX=RC6,RX=RC7 #byte port_PIR1=0x0F9E #define STX 0x02 // STX #define NAK 0x15 // NAK #define ESC 0x1b // ESC #define ACK 0x06 // ACK #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> int n = 0,data; char RX1[16],RX2[16]; char RX1_LCD[17],RX2_LCD[17]; int StartDetect = 0; unsigned long int sum[2]; unsigned long int NakCount = 0; char timed_getc() //タイムアウト付getc() { char returnValue; int32 timeout; timeout = 0; while(!kbhit()&&(++timeout< 100000)) // タイムアウト時間内にデータを受信しなければwhile()ループを抜ける //タイムアウト時間 = 1000 msec delay_us(10); // 10μsec if(kbhit()) //タイムアウト時間内にデータを取得した場合はデータを取得し、そのデータを返す returnValue = getc(); else // タイムアウト時間内でデータを取得できなかった場合はNAKを返す returnValue = NAK; return returnValue; } void DataCatch() // データ取得 { unsigned int Sender_DataSum, //送信側PICが加算したデータ(バイト)の加算合計値(送られてきた加算値) Receiver_DataSum; //受信したデータ(バイト)を 受信側PICが加算した加算合計値 int i; if(n < 16) RX1[n] = data; else if(n < 32) RX2[n-16] = data; // 他なら 文字表示 else if(n < 33) sum[0] = data; else if(n < 34) { sum[1] = data; Sender_DataSum = sum[0] + (sum[1] << 8);//送信側PICが計算したサム(加算値) Receiver_DataSum = 0; for(i = 0; i < 16; i++) Receiver_DataSum = Receiver_DataSum + (unsigned int)RX1[i] + (unsigned int)RX2[i]; //受信側で計算したサム if(Receiver_DataSum == Sender_DataSum) //受信成功なら 液晶に表示 { for(i = 0; i < 16; i++) { RX1_LCD[i] = RX1[i]; RX2_LCD[i] = RX2[i]; } RX1_LCD[16] = '\0'; //1行目データ:文字列データ化 RX2_LCD[16] = '\0'; //2行目データ:文字列データ化 StartDetect = 0; lcd_clear(); printf(lcd_data,RX1_LCD); lcd_cmd(0xC0); //2行目の先頭へ printf(lcd_data,RX2_LCD); putc(ACK); } else { putc(NAK); // NAKを送信→受信失敗を送信側に連絡、再送信を依頼 NakCount++; StartDetect = 0; lcd_clear(); lcd_cmd(0xC0); //2行目の先頭へ printf(lcd_data,"NakCount=%lu",NakCount); } } else StartDetect = 0; n++; } void Receive() // 受信関数 { data = timed_getc(); switch(data) { case ESC: StartDetect = 1; break; case STX: if(StartDetect == 1) //ヘッダーの ESC+STX検出 { StartDetect = 2; n = 0; } else StartDetect = 0; break; default: if(StartDetect == 2)DataCatch(); //データ取得関数 else StartDetect = 0; break; } } main(){ set_tris_c(0b10000000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"First Lines"); lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Second Lines"); delay_ms(500); while(1) { Receive(); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
・下記の写真は送信側PICより整数270を送信した直後のものです。
・送信側PICの液晶の1行目にはACK(サムチェックOK)が受信されたことが表示されています。
・受信側PICには受信されたデータがそのまま表示されています。
送信側PICの液晶 受信側PIC液晶